home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / goodies / qtgraphimp / qtgraphimp.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  12.4 KB  |  438 lines

  1. //////////
  2. //
  3. //    File:        QTGraphImp.c
  4. //
  5. //    Contains:    Sample code for using QuickTime's graphics import routines.
  6. //
  7. //    Written by:    Tim Monroe
  8. //                Based loosely on the SimpleGIExample.c code written by Apple DTS;
  9. //                exporting code based heavily on Dispatch 14 from the Ice Floe by Sam Bushell.
  10. //
  11. //    Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  12. //
  13. //    Change History (most recent first):
  14. //
  15. //       <2>         06/02/98    rtm        added QTGraphImp_ExportGWorldToFile and _GetAvailableExportTypes,
  16. //                                    from Dispatch 14 from the Ice Floe; added QTGraphImp_ExportImageFile
  17. //       <1>         04/14/98    rtm        first file
  18. //       
  19. //    This sample code illustrates how to use QuickTime's graphics importer routines
  20. //    to open and display image files. The graphics importer routines were introduced
  21. //    in QuickTime version 2.5 as a new way to draw still images. The graphics import
  22. //    routines (for example, GetGraphicsImporterForFile) use graphics import components
  23. //    (of component type 'grip') to open and perform other operations on image files.
  24. //    Essentially, you can use the graphics import routines to insulate your application
  25. //    from the nitty gritty details of the image file format and compression used in the
  26. //    image.
  27. //
  28. //    This code also shows how to export images as picture files, and how to determine which
  29. //    formats an image can be exported in. The QT functions that support these operations
  30. //    were introduced in QuickTime version 3.
  31. //
  32. //    In this sample code, we allow the user to open an image file; then we draw it into
  33. //    a window on the screen. Your application, of course, will probably want to do more
  34. //    interesting things with the image. We also allow the user to save an image using JPEG
  35. //    compression.
  36. //
  37. //////////
  38.  
  39. // header files
  40. #include "QTGraphImp.h"
  41.  
  42. // global variables
  43. WindowPtr                        gImageWindow = NULL;    // the window we display the image in
  44. GraphicsImportComponent            gImporter = NULL;
  45.  
  46.  
  47. //////////
  48. //
  49. // QTGraphImp_PromptUserForImageFileAndDisplay
  50. // Let the user select an image file, then display it in a window.
  51. //
  52. //////////
  53.  
  54. void QTGraphImp_PromptUserForImageFileAndDisplay (void)
  55. {
  56.     SFTypeList                    myTypeList;
  57.     StandardFileReply            myReply;
  58.     Rect                        myRect;
  59.     OSErr                        myErr = noErr;
  60.  
  61.     // have the user select an image file;
  62.     // kQTFileTypeQuickTimeImage means any image file readable by GetGraphicsImporterForFile
  63.     myTypeList[0] = kQTFileTypeQuickTimeImage;
  64.  
  65.     StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
  66.     if (!myReply.sfGood)
  67.         goto bail;
  68.     
  69.     //////////
  70.     //
  71.     // get a graphics importer for the image file and determine the natural size of the image
  72.     //
  73.     //////////
  74.  
  75.     myErr = GetGraphicsImporterForFile(&myReply.sfFile, &gImporter);
  76.     if (myErr != noErr)
  77.         goto bail;
  78.     
  79.     myErr = GraphicsImportGetNaturalBounds(gImporter, &myRect);
  80.     if (myErr != noErr)
  81.         goto bail;
  82.     
  83.     //////////
  84.     //
  85.     // create a window to display the image in; then draw into that window
  86.     //
  87.     //////////
  88.     
  89.     MacOffsetRect(&myRect, 50, 50);
  90.     gImageWindow = NewCWindow(NULL, &myRect, myReply.sfFile.name, true, movableDBoxProc, (WindowPtr)-1L, true, 0);
  91.     if (gImageWindow == NULL)
  92.         goto bail;
  93.     
  94.     // set the current port and draw
  95.     GraphicsImportSetGWorld(gImporter, (CGrafPtr)gImageWindow, NULL);
  96.     GraphicsImportDraw(gImporter);
  97.     
  98. bail:
  99.     if (myErr != noErr)
  100.         if (gImporter != NULL)
  101.             CloseComponent(gImporter);
  102. }
  103.  
  104.  
  105. //////////
  106. //
  107. // QTGraphImp_PromptUserForDiskFileAndSaveCompressed
  108. // Let the user select a disk file, then compress the current picture into that file.
  109. //
  110. //////////
  111.  
  112. void QTGraphImp_PromptUserForDiskFileAndSaveCompressed (void)
  113. {
  114.     StandardFileReply            myReply;
  115.     Rect                        myRect;
  116.     GWorldPtr                    myGWorld;
  117.     StringPtr                     myImagePrompt = QTUtils_ConvertCToPascalString(kSaveImagePrompt);
  118.     StringPtr                     myImageFileName = QTUtils_ConvertCToPascalString(kSaveImageFileName);
  119.     OSErr                        myErr = noErr;
  120.  
  121.     // have the user select the name of the new image file
  122.     StandardPutFile(myImagePrompt, myImageFileName, &myReply);
  123.     if (!myReply.sfGood)
  124.         goto bail;
  125.  
  126.     // get the natural size of the image
  127.     myErr = GraphicsImportGetNaturalBounds(gImporter, &myRect);
  128.     if (myErr != noErr)
  129.         goto bail;
  130.  
  131.     // create an offscreen graphics world to draw the image into
  132.     myErr = NewGWorld(&myGWorld, 0, &myRect, NULL, NULL, 0);
  133.     if (myErr == noErr) {
  134.         GraphicsImportSetGWorld(gImporter, (CGrafPtr)myGWorld, NULL);
  135.         GraphicsImportDraw(gImporter);
  136.         
  137.         // save the compressed image
  138.         QTGraphImp_SaveCompressedImage(myGWorld, &myReply.sfFile);
  139.         if (myGWorld != NULL)
  140.             DisposeGWorld(myGWorld);
  141.     }
  142.  
  143. bail:
  144.     free(myImagePrompt);
  145.     free(myImageFileName);
  146. }
  147.  
  148.  
  149. //////////
  150. //
  151. // QTGraphImp_SaveCompressedImage
  152. // Save the current image as a compressed file.
  153. //
  154. //////////
  155.  
  156. void QTGraphImp_SaveCompressedImage (GWorldPtr theWorld, FSSpec *theFile)
  157. {
  158.     ImageDescriptionHandle         myDesc;
  159.     Handle                        myData;
  160.     Rect                        myRect;
  161.     PixMapHandle                myPixMap;    
  162.     CTabHandle                    myCTab = NULL;
  163.     ICMFlushProcRecord            myFlushProc;
  164.     short                        myRefNum;
  165.     short                        myDepth;
  166.     OSErr                        myErr = noErr;
  167.  
  168.     if ((theWorld == NULL) || (theFile == NULL))
  169.         goto bail;
  170.         
  171.     myDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
  172.     if (myDesc == NULL)
  173.         goto bail;
  174.  
  175.     myRect = theWorld->portRect;
  176.     myPixMap = GetGWorldPixMap(theWorld);
  177.     
  178.     if (LockPixels(myPixMap)) {
  179.     
  180.         // if less than 16-bit, then get the color table of our GWorld
  181.         myDepth = (**myPixMap).pixelSize;
  182.         if (myDepth < 16)
  183.             myCTab = (**myPixMap).pmTable;
  184.         
  185.         myData = NewHandle(kBufferSize);
  186.         myErr = MemError();
  187.         
  188.         if ((myData != NULL) && (myErr == noErr)) {
  189.             CodecType            myCodec = kJPEGCodecType;
  190.             
  191.             HLock(myData);
  192.                                                          
  193.             myErr = FSpCreate(theFile, kImageFileCreator, kQTFileTypeJPEG, 0);
  194.             
  195.             if (myErr == noErr)
  196.                 myErr = FSpOpenDF(theFile, fsRdWrPerm, &myRefNum);
  197.                 
  198.             if (myErr == noErr)
  199.                 myErr = SetFPos(myRefNum, fsFromStart, 0);
  200.                 
  201.             if (myErr == noErr) {
  202.                 ICMFlushProcRecordPtr        myFlushProcPtr = NULL;
  203.                 
  204. #if USE_FLUSH_PROC
  205.                 myFlushProc.flushProc = NewICMFlushProc(QTGraphImp_DataUnloadProc);
  206.                 myFlushProc.flushRefCon = myRefNum;
  207.                 myFlushProcPtr = &myFlushProc;
  208. #else
  209.                 myFlushProcPtr = NULL;
  210. #endif
  211.                 // compress the image
  212.                 myErr = FCompressImage(    myPixMap,
  213.                                         &myRect,
  214.                                         myDepth,
  215.                                          codecNormalQuality,
  216.                                          myCodec,
  217.                                         anyCodec,
  218.                                         myCTab,
  219.                                          codecFlagWasCompressed,
  220.                                          kBufferSize,
  221.                                          myFlushProcPtr,
  222.                                          NULL,
  223.                                          myDesc,
  224.                                          *myData);
  225.             
  226. #if !USE_FLUSH_PROC
  227.                 if (myErr == noErr)
  228.                     myErr = FSWrite(myRefNum, &(**myDesc).dataSize, *myData);
  229. #endif
  230.                 
  231.                 if (myErr == noErr)
  232.                     myErr = SetFPos(myRefNum, fsFromStart, (**myDesc).dataSize);
  233.  
  234.                 if (myErr == noErr)
  235.                     myErr = SetEOF(myRefNum, (**myDesc).dataSize);
  236.                              
  237.                 if (myErr == noErr)        
  238.                     myErr = FSClose(myRefNum);
  239.                 
  240.                 HUnlock(myData);
  241.                 DisposeHandle(myData);
  242.                 
  243. #if USE_FLUSH_PROC
  244.                 DisposeRoutineDescriptor(myFlushProc.flushProc);
  245. #endif
  246.             }
  247.         }
  248.     }
  249.     
  250.     UnlockPixels(myPixMap);
  251.  
  252. bail:    
  253.     if (myDesc != NULL)
  254.         DisposeHandle((Handle)myDesc);
  255. }            
  256.  
  257.  
  258. //////////
  259. //
  260. // QTGraphImp_DataUnloadProc
  261. // A data unloading procedure: write the compressed data to disk.
  262. //
  263. // The theRefCon parameter is assumed to be a file reference number of an open file.
  264. //
  265. //////////
  266.  
  267. PASCAL_RTN OSErr QTGraphImp_DataUnloadProc (Ptr theData, long theBytesNeeded, long theRefCon)
  268. {
  269.     OSErr        myErr = noErr;
  270.     
  271.     if (theData == NULL) {
  272.         // if data is NULL, set a new position in the file from the current mark, offset by bytesNeeded
  273.         myErr = SetFPos(theRefCon, fsFromMark, theBytesNeeded);
  274.     } else {
  275.         // otherwise, write the specified data to disk
  276.         myErr = FSWrite(theRefCon, &theBytesNeeded, theData);
  277.     }
  278.     
  279.     return(myErr);
  280. }
  281.  
  282.  
  283. //////////
  284. //
  285. // QTGraphImp_ExportGWorldToFile
  286. // Save the image in a graphics world to the specified file.
  287. //
  288. // Use this function when you've got an image that you want to export to a file
  289. // but that image wasn't read in from a file (in which case you could just use
  290. // the GetGraphicsImporterForFile function to open an appropriate graphics importer).
  291. //
  292. // Based on the function ExportGWorldToFile in Dispatch 14 from the Ice Floe.
  293. //
  294. //////////
  295.  
  296. OSErr QTGraphImp_ExportGWorldToFile (GWorldPtr theWorld, FSSpec *theFile, OSType theType)
  297. {
  298.     PicHandle                    myPicture = NULL;
  299.     GraphicsImportComponent        myImporter = NULL;
  300.     Handle                        myHandle = NULL;
  301.     CGrafPtr                    mySavedGW;
  302.     GDHandle                    mySavedGD;
  303.     OSErr                        myErr = noErr;
  304.  
  305.     // save the current graphics world, and set the specified graphics world as current
  306.     GetGWorld(&mySavedGW, &mySavedGD);
  307.     SetGWorld(theWorld, NULL);
  308.  
  309.     // capture the contents of the specified graphics world in a picture handle
  310.     myPicture = OpenPicture(&((GrafPtr)theWorld)->portRect);
  311.     CopyBits(    &((GrafPtr)theWorld)->portBits,
  312.                 &((GrafPtr)theWorld)->portBits,
  313.                 &((GrafPtr)theWorld)->portRect,
  314.                 &((GrafPtr)theWorld)->portRect,
  315.                 srcCopy,
  316.                 NULL);
  317.                   
  318.     ClosePicture();
  319.  
  320.     // convert the picture handle into a handle-based PICT file by adding a 512-byte header to the start;
  321.     // picture files are just like picture handles, except that they have an extra 512-byte header at the
  322.     // front; any data in this header is usually ignored but it must exist, for historical reasons
  323.     myHandle = NewHandleClear(512);
  324.     myErr = MemError();
  325.     if (myErr != noErr)
  326.         goto bail;
  327.  
  328.     myErr = HandAndHand((Handle)myPicture, myHandle);
  329.     if (myErr != noErr)
  330.         goto bail;
  331.  
  332.     // open an instance of the picture file graphics importer
  333.     myErr = OpenADefaultComponent(GraphicsImporterComponentType, kQTFileTypePicture, &myImporter);
  334.     if (myErr != noErr)
  335.         goto bail;
  336.  
  337.     myErr = GraphicsImportSetDataHandle(myImporter, myHandle);
  338.     if (myErr != noErr)
  339.         goto bail;
  340.  
  341.     // export the image to a file
  342.     myErr = GraphicsImportExportImageFile(myImporter, theType, kImageFileCreator, theFile, smSystemScript);
  343.  
  344. bail:
  345.     // restore the original graphics world
  346.     SetGWorld(mySavedGW, mySavedGD);
  347.     
  348.     if (myPicture != NULL)
  349.         KillPicture(myPicture);
  350.     
  351.     if (myImporter != NULL)
  352.         CloseComponent(myImporter);
  353.     
  354.     if (myHandle != NULL)
  355.         DisposeHandle(myHandle);
  356.     
  357.     return(myErr);
  358. }
  359.  
  360.  
  361. //////////
  362. //
  363. // QTGraphImp_GetAvailableExportTypes
  364. // Get a list of the available image export file types.
  365. //
  366. // Based on a function in Dispatch 14 from the Ice Floe.
  367. //
  368. //////////
  369.  
  370. OSErr QTGraphImp_GetAvailableExportTypes (GraphicsImportComponent theImporter)
  371. {
  372.     QTAtomContainer                myContainer = NULL;
  373.     short                        myCount, myIndex;
  374.     OSErr                        myErr = noErr;
  375.  
  376.     // get an atom container that contains one or more kGraphicsExportGroup atoms;
  377.     // each export group atom represents a single export format and has child atoms that indicate
  378.     // the file type (kGraphicsExportFileType), a human-readable name (kGraphicsExportDescription),
  379.     // a file extension (kGraphicsExportExtension) and a MIME type (kGraphicsExportMIMEType)
  380.     myErr = GraphicsImportGetExportImageTypeList(theImporter, &myContainer);
  381.     if (myErr != noErr)
  382.         goto bail;
  383.  
  384.     myCount = QTCountChildrenOfType(myContainer, kParentAtomIsContainer, kGraphicsExportGroup);
  385.     for (myIndex = 1; myIndex <= myCount; myIndex++) {
  386.         QTAtom                    myGroupAtom;
  387.  
  388.         myGroupAtom = QTFindChildByIndex(myContainer, kParentAtomIsContainer, kGraphicsExportGroup, myIndex, NULL);
  389.         if (myGroupAtom != 0) {
  390.             QTAtom                myTypeAtom;
  391.             
  392.             myTypeAtom = QTFindChildByIndex(myContainer, myGroupAtom, kGraphicsExportFileType, 1, NULL);
  393.             if (myTypeAtom != 0) {
  394.                 OSType            myType;
  395.                 
  396.                 myErr = QTCopyAtomDataToPtr(myContainer, myTypeAtom, false, sizeof(myType), &myType, NULL);
  397.                 // the data in QT atoms is always big-endian, so convert the file type to native format
  398.                   myType = EndianU32_BtoN(myType);
  399.                 
  400.                 // at this point, you probably want to do something interesting with the file type, eh?
  401.                 // this is left as an exercise for the reader
  402.                 
  403.             } else {
  404.                 myErr = cannotFindAtomErr;
  405.             }
  406.         }
  407.     }
  408.  
  409. bail:
  410.     if (myContainer != NULL)
  411.         QTDisposeAtomContainer(myContainer);
  412.     return(myErr);
  413. }
  414.  
  415.  
  416. //////////
  417. //
  418. // QTGraphImp_ExportImageFile
  419. // Let the user select a disk file, then export the current picture into that file.
  420. //
  421. //////////
  422.  
  423. OSErr QTGraphImp_ExportImageFile (GraphicsImportComponent theImporter)
  424. {
  425.     OSType                    myType;
  426.     FSSpec                    myFSSpec;
  427.     OSErr                    myErr = noErr;
  428.  
  429.     myErr = GraphicsImportDoExportImageFileDialog(
  430.                             theImporter, 
  431.                             NULL,             // no default name for the file
  432.                             NULL,             // use the default prompt in the dialog box
  433.                             NULL,             // no modal dialog filter procedure
  434.                             &myType,         // return the type of the selected file
  435.                             &myFSSpec,         // return the name (etc.) of the selected file
  436.                             NULL);            // don't return the script code
  437.     return(myErr);
  438. }